/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.examples.modules.globalactions;
import java.beans.*;
import java.util.*;
import java.io.*;
import javax.swing.*;
import org.openide.*;
import org.openide.actions.ExecuteAction;
import org.openide.cookies.InstanceCookie;
import org.openide.execution.*;
import org.openide.filesystems.*;
import org.openide.loaders.*;
import org.openide.modules.ModuleInstall;
import org.openide.util.RequestProcessor;
/** Install {@link TestAction} into the main window's menu and toolbar.
*
* <p>Feel free to copy-and-paste pieces of this implementation for your own
* install code, if you are doing similar things.
*/
public class Install extends ModuleInstall {
// Arbitrary names. They ensure that the file name is unique.
// (More important for the separator since its class will be common.)
// Generally, a more specific name would be a good idea to avoid
// conflicts.
// null could be used if the instance class is obviously from your
// module, but using a specific name is more descriptive.
// Note that this name does NOT affect the display name of the action!
private static final String ACTION_NAME = "MyTestAction";
private static final String SEP_NAME = "MyTestActionSeparator";
/** Install actions.
* Adds the {@link TestAction} to the top of the Tools menu (with an intervening separator);
* and to the end of the Data toolbar (with a toolbar separator).
*
* <p>Note that the {@link TestServiceAction} is completely handled by the manifest.
* For {@link TestAction}, placing it in the manifest would add it as a service action,
* which is permissible but unnecessary since it is installed specially here.
*
* <p>Also installs startup file for keybindings.
*
* <p>[PENDING] Should also install the actions into the actions pool for full user customizability.
*/
public void installed () {
try {
installInstance (getMenuFolder (), SEP_NAME, JSeparator.class, true);
installInstance (getMenuFolder (), ACTION_NAME, TestAction.class, true);
installInstance (getToolbarFolder (), SEP_NAME, JToolBar.Separator.class, false);
installInstance (getToolbarFolder (), ACTION_NAME, TestAction.class, false);
installInstance (getPoolFolder (), ACTION_NAME, TestAction.class, false);
// Startup file.
InputStream is = null;
try {
// First retrieve the desired contents from the module resource.
// It is only for convenience that this is stored as a separate file in the module.
is = Install.class.getClassLoader ().getResourceAsStream
("org/netbeans/examples/modules/globalactions/GlobalActionsKeys.java_");
if (is == null) System.err.println ("Resource not found");
FileObject startup = TopManager.getDefault ().getPlaces ().folders ().startup ().getPrimaryFile ();
// Never try to overwrite an existing startup file.
if (startup.getFileObject ("GlobalActionsKeys", "java") == null) {
FileObject gakFile = startup.createData ("GlobalActionsKeys", "java");
// Write the proper contents to it.
FileLock lock = null;
try {
lock = gakFile.lock ();
OutputStream os = null;
try {
os = gakFile.getOutputStream (lock);
byte[] buf = new byte[1024];
int count;
while ((count = is.read (buf)) != -1)
os.write (buf, 0, count);
} finally {
if (os != null) os.close ();
}
} finally {
if (lock != null) lock.releaseLock ();
}
try {
final DataObject gak = DataObject.find (gakFile);
if (gak instanceof MultiDataObject) {
// Set internal execution. This property will be stored on disk.
ExecSupport.setExecutor (((MultiDataObject) gak).getPrimaryEntry (), Executor.find (ThreadExecutor.class));
// (Compile and) execute it now in a separate thread.
// This could take a couple of seconds, so do not block during module install,
// doing so might cause a deadlock.
RequestProcessor.postRequest (new Runnable () {
public void run () {
// This runs it appropriately, compiling first.
ExecuteAction.execute (new DataObject[] { gak }, true);
}
});
} else {
// Will not happen with standard Java module, but to be safe:
System.err.println ("Not a MultiDataObject");
gak.delete ();
}
} catch (DataObjectNotFoundException donfe) {
donfe.printStackTrace ();
}
}
} finally {
if (is != null) is.close ();
}
} catch (IOException ioe) {
ioe.printStackTrace ();
}
}
/** Uninstall the same actions we previously installed.
* Conditionally removes keybinding startup file as well.
*/
public void uninstalled () {
try {
uninstallInstance (getMenuFolder (), SEP_NAME, JSeparator.class);
uninstallInstance (getMenuFolder (), ACTION_NAME, TestAction.class);
uninstallInstance (getToolbarFolder (), SEP_NAME, JToolBar.Separator.class);
uninstallInstance (getToolbarFolder (), ACTION_NAME, TestAction.class);
uninstallInstance (getPoolFolder (), ACTION_NAME, TestAction.class);
// Startup file.
FileObject gakFile = TopManager.getDefault ().getPlaces ().folders ().startup ().
getPrimaryFile ().getFileObject ("GlobalActionsKeys", "java");
// Only delete if still exists and user permits it.
// User might have made valuable modifications they would wish to
// save elsewhere.
if (gakFile != null &&
NotifyDescriptor.OK_OPTION ==
TopManager.getDefault ().notify (new NotifyDescriptor.Confirmation
("Do you want to delete file Startup/GlobalActionsKeys.java?",
"Uninstalling Global Actions"))) {
try {
// Delete the whole data object, not just the file;
// otherwise the .class will remain.
DataObject gak = DataObject.find (gakFile);
gak.delete ();
} catch (DataObjectNotFoundException donfe) {
donfe.printStackTrace ();
}
}
} catch (IOException e) {
e.printStackTrace ();
}
}
/** Get the folder to install menu items in.
* @return the folder
*/
private static DataFolder getMenuFolder () throws IOException {
return DataFolder.create (TopManager.getDefault ().getPlaces ().folders ().menus (), "Tools");
}
/** Get the folder to install toolbar items in.
* @return the folder
*/
private static DataFolder getToolbarFolder () throws IOException {
return DataFolder.create (TopManager.getDefault ().getPlaces ().folders ().toolbars (), "Data");
}
/** Get the folder for the actions pool.
* @return the folder
*/
private static DataFolder getPoolFolder () throws IOException {
return DataFolder.create (TopManager.getDefault ().getPlaces ().folders ().actions (), "GlobalActions");
}
/** Install an instance into a folder.
* @param where the folder to add to
* @param name the (data-object) name of the instance
* @param clazz the instance class that will be instantiated in the system object
* @param atFront <code>true</code> to place at the beginning of the folder; <code>false</code> to place at the end
*/
private void installInstance (final DataFolder where, String name, Class clazz, boolean atFront) throws IOException {
if (InstanceDataObject.find (where, name, clazz) != null) return;
final InstanceDataObject ido = InstanceDataObject.create (where, name, clazz);
List newkids = new ArrayList ();
if (atFront) newkids.add (ido);
DataObject[] oldkids = where.getChildren ();
int seen = 0;
for (int i = 0; i < oldkids.length; i++) {
DataObject kid = oldkids[i];
// DataObject==DataObject should work, but just to be safe:
if (kid.equals (ido))
seen++;
else
newkids.add (kid);
}
if (! atFront) newkids.add (ido);
if (seen != 1) System.err.println ("Saw instance data object " + name + " " + seen + " (!= 1) times!");
where.setOrder ((DataObject[]) newkids.toArray (new DataObject[newkids.size ()]));
}
/** Uninstall an instance from a folder.
* Also removes the folder if there was nothing else in it.
* @param where folder to uninstall from
* @param name instance name
* @param clazz instance class
*/
private void uninstallInstance (DataFolder where, String name, Class clazz) throws IOException {
if (! InstanceDataObject.remove (where, name, clazz))
throw new IOException ("Could not remove instance " + name + " (reason unknown)");
if (where.getChildren ().length == 0)
where.delete ();
}
/** Restore the module.
* In this case does nothing--the instances are already on disk.
*/
public void restored () {
}
/** Permit the IDE to be closed.
* @return <code>true</code> to permit it
*/
public boolean closing () {
return true;
}
/** Test main method. */
public static void main (String[] args) {
if (args.length != 1) throw new RuntimeException ();
if (args[0].equals ("install"))
new Install ().installed ();
else if (args[0].equals ("uninstall"))
new Install ().uninstalled ();
else
throw new RuntimeException ();
}
}